package com.huixiong.nio.channel.server.nioserver;

import lombok.SneakyThrows;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * nio 实现 client server 通信
 * TODO 有bug
 *
 * @author timothy.yang cloudwise
 * @since 2022-05-08 20:57
 */
public class NioServer extends Thread {
    ServerSocketChannel serverSocket;

    @Override
    public void run() {
        try {
            Selector selector = Selector.open();
            serverSocket = ServerSocketChannel.open();
            serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 12345));
            serverSocket.configureBlocking(false);

            // 注册到 Selector
            serverSocket.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                // 阻塞等待就绪到 Channel
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iter = selectionKeys.iterator();
                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    // 生产系统中一半会额外进行就绪状态检查
                    for (int i = 0; i < 10; i++) {
                        sayHelloWorld((ServerSocketChannel) key.channel());
                    }
                    iter.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sayHelloWorld(ServerSocketChannel channel) {
        try {
            SocketChannel client = channel.accept();
            client.write(Charset.defaultCharset().encode("Hello world!"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SneakyThrows
    public static void main(String[] args) {
        NioServer nioServer = new NioServer();
        nioServer.start();
        try {
            Socket client = new Socket(InetAddress.getLocalHost(), 12345);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            bufferedReader.lines().forEach(
                    System.out::println
            );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
